package com.zlsy.secondtime.threadcoreknowledge.volatiledemo;

import org.apache.commons.lang3.concurrent.BasicThreadFactory;

import java.util.concurrent.*;

/**
 * @author zhouliang
 * @date 2020/5/15 14:51
 * <p>
 * 当陷入阻塞的时候，volatile是无法停止线程的。
 */
public class WrongWayVolatileCannotStop {

    static class Product implements Runnable {
        private volatile boolean canceled = false;
        private BlockingQueue blockingDeque;

        public Product(BlockingQueue blockingDeque) {
            this.blockingDeque = blockingDeque;
        }

        @Override
        public void run() {
            int num = 0;
            try {
                while (num <= 100000 && !canceled) {
                    if (num % 100 == 0) {
                        //当生产者速度大于消费者的时候，线程会阻塞在这里，虽然canceled被设置为true了
                        //volatile也保证消费者线程可以看到true的值，但是走不到!canceled这个代码，因为阻塞在这里了。
                        //所以说用volatile来停止线程是不够全面的。
                        blockingDeque.put(num);
                        System.out.println("num: " + num + "是一百的倍数，被放到队列中了。");
                    }
                    num++;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("生产者结束运行！");
            }
        }
    }

    static class Consumer {

        private BlockingQueue blockingQueue;

        public Consumer(BlockingQueue blockingQueue) {
            this.blockingQueue = blockingQueue;
        }

        private boolean isConsumered() {
            return (Math.random() < 0.95);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        BasicThreadFactory threadFactory = new BasicThreadFactory.Builder().namingPattern("test-%s").build();
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
                1,
                1,
                0L,
                TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<>(1024),
                threadFactory);
        BlockingQueue blockingQueue = new ArrayBlockingQueue<>(10);
        Product product = new Product(blockingQueue);
        poolExecutor.execute(product);

        Thread.sleep(1000);

        Consumer consumer = new Consumer(blockingQueue);
        while (consumer.isConsumered()) {
            System.out.println(consumer.blockingQueue.take() + "被消费了！");
            Thread.sleep(100);
        }
        System.out.println("消费者不需要更多的数据了。");
        product.canceled = true;

        System.out.println("canceled:" + product.canceled);

        poolExecutor.shutdown();
    }
}
